﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using OBID;


namespace RFIDWriterClass
{
    class WriteClass :  FeIscListener
    {
        private FedmIscReader fedm;
        private string TransponderSerialNumber;
        private byte TransponderSerialNumberLength;
        private uint persistenceResetTime = 0;

        byte[] CustomerIDArray = new byte[4];

        #region declaration from delegatetyp
        public delegate void DelegateTagChanged(string[] serialNumber, byte[] tagType);
        public delegate void DelegateLastError(string err);
        public delegate void DelegateNoTag(int readerStatus);
        public delegate void DelegateOnSendProtocol(string sendprotocol);
        public delegate void DelegateOnReceiveProtocol(string receiveprotocol); 
        #endregion

        

        private Boolean PrepareTransponder()
        {
            byte bTagType;
            // get Tag Type // 0 als erster parameter da nur eine Transponder-Seriennummer möglich --> die daher auf id = 0
            fedm.GetTableData(0, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_TRTYPE, out bTagType);

            //seriennumemr haben wir bereits als globale variable
            TransponderSerialNumberLength = Convert.ToByte(TransponderSerialNumber.Length / 2);
            try
            {
                fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_UID, TransponderSerialNumber); // prepare for 0xB0 command
                if (bTagType == FedmIscReaderConst.TR_TYPE_ISO14443A ||
                bTagType == FedmIscReaderConst.TR_TYPE_ISO14443B)
                {
                    fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B2_REQ_UID, TransponderSerialNumber); // prepare for 0xB2 command
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
                return false;
            }

            return true;
        }

        private Boolean Write()
        {
            byte[] data;
            int blockSize;
            int dbn;
            int address;
            int idx;
            int mode;
            long datalocation = FedmIscReaderConst.DATA_TxDB;

            int iBack = 0;


            mode = Konstanten.mode;

            // set IscTable-Parameter
            dbn = Konstanten.dbn;
            address = Konstanten.address; 
            blockSize = Konstanten.blockSize;

            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_CMD, 0x24); // write multiple blocks
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_DBN, dbn);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_DB_ADR, address);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE, mode);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_UID, TransponderSerialNumber);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_REQ_DB_SIZE, blockSize);

            idx = fedm.FindTableIndex(0, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_SNR, TransponderSerialNumber);

            FedmTableItem item;
            try
            {
                item = fedm.GetTableItem(idx, FedmIscReaderConst.ISO_TABLE);
            }
            catch (System.Exception ex)
            {
                //MessageBox.Show(this, ex.ToString(), "Error");
                return false;
            }

            //Blocksize setzen
            item.SetData(FedmIscReaderConst.DATA_BLOCK_SIZE, blockSize);

            //KundenID aus Array an RFID-Treiber übergeben
             for (int i = address; i <= address + (dbn - 1); i++)
            {
                //data mit Daten aus unserem KundenID-Array füllen
                data = CustomerIDArray;

                //Ausgelesene Daten in "Ausgang" schreiben
                item.SetData(datalocation, i, data);
            }

            try
            {
                iBack = fedm.SetTableItem(idx, item);

                //Send WriteMultipleBlocks-Protocol - Ausführen
                iBack = fedm.SendProtocol(0xB0);
            }
            catch (System.Exception ex)
            {
                return false;
            }

            return true;
        }

        private Boolean DetectTag()
        {
            
            int readerStatus = 0;
            string[] serialNumber;
            byte[] tagType;

            //declaration from delegateobject 
            DelegateTagChanged TagChangedMethod = new DelegateTagChanged(TagChanged);
            DelegateLastError LastErrorMethod = new DelegateLastError(LastError);
            DelegateNoTag NoTagMethod = new DelegateNoTag(ClearList);

            object[] obj1 = new object[2];
            object obj2 = null;
            IAsyncResult result;


            //vorher schleife
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_CMD, 0x01);
            fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE, 0x00);
            try
            {
                fedm.ResetTable(FedmIscReaderConst.ISO_TABLE);
                fedm.SendProtocol(0x69); // RFReset
                readerStatus = fedm.SendProtocol(0xB0); // ISOCmd
                if (readerStatus != 0 && readerStatus != 0x94)
                {
                    //No Tag
                    //obj2 = readerStatus;
                    NoTagMethod(readerStatus);
                    //result = BeginInvoke(NoTagMethod, obj2);
                    //EndInvoke(result);
                    return false;
                }

                while (fedm.GetLastStatus() == 0x94) // more flag set?
                {
                    fedm.SetData(FedmIscReaderID.FEDM_ISC_TMP_B0_MODE_MORE, 0x01);
                    fedm.SendProtocol(0xB0);
                }
                //new dimensiion from array serialNumber,tagtype,SeNumbLength
                serialNumber = new string[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];
                tagType = new byte[fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE)];

                if (fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE) <= 0)
                {
                    //No Table
                    return false;
                }

                int i;
                for (i = 0; i < fedm.GetTableLength(FedmIscReaderConst.ISO_TABLE); i++)
                {
                    fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_SNR, out serialNumber[i]);
                    fedm.GetTableData(i, FedmIscReaderConst.ISO_TABLE, FedmIscReaderConst.DATA_TRTYPE, out tagType[i]);
                }

                //Seriennummer
                obj1[0] = serialNumber;

                //asynchrone result senden
                TagChangedMethod(serialNumber, null);
                //result = BeginInvoke(TagChangedMethod, obj1);
                //EndInvoke(result);
                return true;

            }
            catch (Exception ex)
            {
                //Fehler
                obj2 = ex.ToString();
                //asynchrone result senden
                LastErrorMethod(ex.ToString());
                //result = BeginInvoke(LastErrorMethod, obj2);
                //EndInvoke(result);
                return false;
            }
        }

        #region Delegated Methode to show protocol
        /******************** Methode to show protocol*****************************/

        //show sent Protocol
        public void DisplaySendProtocol(string protocol)
        {
            //if (this.checkBoxEnable.Checked)
            //{
            //    this.textBoxProtocol.Text += protocol;
            //}
        }

        //show received protocol
        public void DisplayReceiveProtocol(string protocol)
        {
            //if (this.checkBoxEnable.Checked)
            //{
            //    this.textBoxProtocol.Text += protocol;
            //}
        }

        /********************************END****************************************/
        
        #endregion


        #region Methode from interface FeIscListener
        /*********************************Methode from interface FeIscListener**********************************************/

        public void OnReceiveProtocol(FedmIscReader reader, byte[] receiveProtocol)
        {
        }

        public void OnReceiveProtocol(FedmIscReader reader, String receiveProtocol)
        {
            //IAsyncResult result;
            //DelegateOnReceiveProtocol ReceiveProtocolMethod = new DelegateOnReceiveProtocol(DisplayReceiveProtocol);
            //result = (IAsyncResult)Invoke(ReceiveProtocolMethod, receiveProtocol);

        }

        public void OnSendProtocol(FedmIscReader reader, byte[] sendProtocol)
        {
        }

        public void OnSendProtocol(FedmIscReader reader, String sendProtocol)
        {
            //IAsyncResult result;
            //DelegateOnSendProtocol SendProtocolMethod = new DelegateOnSendProtocol(DisplaySendProtocol);
            //result = (IAsyncResult)Invoke(SendProtocolMethod, sendProtocol);
        }

        /************************************************************END********************************************************/
        
        #endregion

        #region Delegated methods
        /*******************Methode to show asynchrone Result in GUI****************/

        //Show message error                                                      
        public void LastError(string err)
        {
            MessageBox.Show(err);
        }

        //Clear tag list
        public void ClearList(int readerStatus)
        {
            this.TransponderSerialNumber = "0000";
        }

        //Show multiple TranspondersID                                           
        public void TagChanged(string[] serialNumber, byte[] tagType)
        {
            if (serialNumber.Length > 1)
            {
                this.TransponderSerialNumber = "0000";

                //WriteGui.Set_lb_TagScanResult("Bitte nur einen Transponder vor den RFID-Reader halten");
            }
            else
            {
                //Ausreichend da nur eine seriennumer - Prüfe ob wirklich in 0
                this.TransponderSerialNumber = serialNumber[0];
                PrepareTransponder();
            }

        }

        /****************************************END*********************************/
        
        #endregion


        public Boolean SetCustomerID(string CustomerID)
        {
            TransponderSerialNumber = "0000";
            CustomerIDArray = Helperclass.StringToByteArray(CustomerID);

            for (int i = 0; i <= 3; i++)
            {
                if (DetectTag() == true && TransponderSerialNumber != "0000")
                    break;
                else
                {
                    //Wartefunktion ohne gui-freeze
                }
            }
            //Testweise
            //lb_TagScanResult.Text = this.TransponderSerialNumber;
            if (TransponderSerialNumber != "0000")
            {
                Write();
                return true;
            }
            else
            {
                return false;
            }

        }

        public void CloseReader()
        {
            //remove Events 
            fedm.RemoveEventListener(this, FeIscListenerConst.SEND_STRING_EVENT);
            fedm.RemoveEventListener(this, FeIscListenerConst.RECEIVE_STRING_EVENT);

            if (fedm.Connected == true)
            {
                // set Persistence Reset Time in Reader Configuration back to old value
                int back = OBID.Fedm.ERROR_UNSUPPORTED_NAMESPACE;
                try
                {
                    back = fedm.TestConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime);
                }
                catch (Exception ex)
                { // ignore Exception
                }
                // if reader supports this parameter, set it back to old value !
                if (0 == back)
                {
                    try
                    {
                        back = fedm.SetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, persistenceResetTime, false);
                        if (back == 1) // return value 1 indicates modified parameter
                            back = fedm.ApplyConfiguration(false);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString(), "Error");
                    }
                }
            }
        }

        public Boolean InitializeReader()
        {
            //Neues Readerobjekt erstellen
            try
            { 
                fedm = new FedmIscReader();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

            //Verbinde USB-Reader
            fedm.SetTableSize(FedmIscReaderConst.ISO_TABLE, 128);
            try
            {
                fedm.ConnectUSB(0);
            }
            catch (FePortDriverException ex)
            {
                MessageBox.Show(ex.ToString(), "Error");
            }


            if (fedm.Connected == true)
            {
                //### Liest die gesamte Leserkonfiguration aus.
                try
                {
                    fedm.ReadCompleteConfiguration(false);
                }
                catch (Exception ex)
                {
                    MessageBox.Show( ex.ToString());
                }

                // set Persistence Reset Time in Reader Configuration to zero
                // this speeds up inventory cycles
                int back = OBID.Fedm.ERROR_UNSUPPORTED_NAMESPACE;

                //### Testet ob ein Parametername vom  eingestellten Lesertyp unterstützt wird
                try
                {
                    back = fedm.TestConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime);
                }
                catch (Exception ex)
                { // ignore Exception
                }

                byte ucReaderMode;
                fedm.GetConfigPara(OBID.ReaderConfig.OperatingMode.Mode, out ucReaderMode, true);

                MessageBox.Show(ucReaderMode.ToString());

                // if reader supports this parameter, set it !
                if (0 == back)
                {
                    try
                    {
                        back = fedm.GetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, out persistenceResetTime, false);
                        back = fedm.SetConfigPara(OBID.ReaderConfig.Transponder.PersistenceReset.Antenna.No1.PersistenceResetTime, (uint)0, false);
                        if (back == 1) // return value 1 indicates modified parameter
                            back = fedm.ApplyConfiguration(false);

                        fedm.GetConfigPara(OBID.ReaderConfig.OperatingMode.Mode, out ucReaderMode, true);

                        MessageBox.Show(ucReaderMode.ToString());
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
            }



            if (fedm.Connected == true)
            {
                //Registry from Events send and receive
                fedm.AddEventListener(this, FeIscListenerConst.SEND_STRING_EVENT);
                fedm.AddEventListener(this, FeIscListenerConst.RECEIVE_STRING_EVENT);
                return true;
            }
            else
            {
                MessageBox.Show("Not Connected");
                return false;
            }
        }

        //Construktor, Reader Verbinden, Eventhandler, Threat
        public WriteClass()
        {
            InitializeReader();
        }
    }
}
